package com.db.priceApp.network.protocol;

import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Logger;

public class MessageTranciever {
	private static final int DEFAULT_BUFFER_SIZE = 1024;

	private ByteBuffer readBuffer;
	private Queue<byte[]> messages = new LinkedList<>();
	private Logger logger = Logger.getLogger(MessageTranciever.class.getName());

	public MessageTranciever() {
		readBuffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
	}

	public void receive(ReadableByteChannel channel) throws IOException {
		synchronized (channel) {			
			if (channel.read(readBuffer) < 0) {
				throw new IOException("IO error occured while reading from the channel");
			}
			
			byte[] message;
			while ((message = readSingleMessage()) != null) {
				messages.add(message);
			}		
		}
	}

	public boolean hasMessage() {
		return !messages.isEmpty();
	}

	public byte[] nextMessage() {
		return messages.poll();
	}

	public void transmit(byte[] message, WritableByteChannel channel)
			throws IOException {
		int totalLength = message.length + 1;
		ByteBuffer buffer = ByteBuffer.allocate(totalLength);
		buffer.put(message);
		byte b = '%';
		buffer.put(b);
		buffer.flip();
		synchronized (channel) {			
			channel.write(buffer);
		}
	}

	private byte[] readSingleMessage() {
		
		readBuffer.flip();
		byte[] message = new byte[readBuffer.limit()];
		
		if(readBuffer.position() >= readBuffer.limit()){
			readBuffer.position(readBuffer.limit());
			readBuffer.limit(readBuffer.capacity());
			return null;
		}

		try {
			byte b = readBuffer.get();
			int i;
			for (i = 0; b != '%'; i++) {
				message[i] = b;
				b = readBuffer.get();
			}
			byte[] messg = new byte[i];
			for(int j = 0; j < i; j++) {
				messg[j] = message[j];
			}
			readBuffer.compact();	
			return messg;
		} catch (BufferUnderflowException e) {
			logger.warning("fail to receive message correctly: buffer overflow");
			return null;
		}
	}
}
